home *** CD-ROM | disk | FTP | other *** search
/ The Complete Utilities To…ka 501 Killer Utilities! / 501 Killer Utilities! (Macworld July 1995).cdr / Programming / OutOfPhase1.1 Source / OutOfPhase Folder / TrackEffectGenerator.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-06  |  21.2 KB  |  606 lines  |  [TEXT/KAHL]

  1. /* TrackEffectGenerator.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #define ShowMe_NoteObjectRec
  31. #include "TrackEffectGenerator.h"
  32. #include "EffectSpecList.h"
  33. #include "Memory.h"
  34. #include "DelayLine.h"
  35. #include "BinaryCodedDecimal.h"
  36. #include "LinearTransition.h"
  37. #include "NoteObject.h"
  38. #include "IncrementalParameterUpdator.h"
  39. #include "NLProc.h"
  40. #include "FilterArray.h"
  41. #include "Analyzer.h"
  42.  
  43.  
  44. typedef struct CommandConsCell
  45.     {
  46.         /* link.  only forward link used since insertion sorting is not necessary */
  47.         struct CommandConsCell*        Next;
  48.  
  49.         /* command that has been suspended */
  50.         NoteObjectRec*                        Command;
  51.  
  52.         /* this is the start time of the note, used for ordering the scanning gap list */
  53.         long                                            StartTime;
  54.     } CommandConsCell;
  55.  
  56.  
  57. typedef struct OneEffectRec
  58.     {
  59.         struct OneEffectRec*        Next;
  60.         EffectTypes                            Type;
  61.         union
  62.             {
  63.                 DelayLineRec*                        DelayEffect;
  64.                 NLProcRec*                            NLProcEffect;
  65.                 FilterArrayRec*                    FilterEffect;
  66.                 AnalyzerRec*                        AnalyzerEffect;
  67.             } u;
  68.     } OneEffectRec;
  69.  
  70.  
  71. struct TrackEffectGenRec
  72.     {
  73.         LargeBCDType                        CurrentAccent1;
  74.         struct LinearTransRec*    Accent1Change;
  75.         long                                        Accent1ChangeCountdown;
  76.  
  77.         LargeBCDType                        CurrentAccent2;
  78.         struct LinearTransRec*    Accent2Change;
  79.         long                                        Accent2ChangeCountdown;
  80.  
  81.         LargeBCDType                        CurrentAccent3;
  82.         struct LinearTransRec*    Accent3Change;
  83.         long                                        Accent3ChangeCountdown;
  84.  
  85.         LargeBCDType                        CurrentAccent4;
  86.         struct LinearTransRec*    Accent4Change;
  87.         long                                        Accent4ChangeCountdown;
  88.  
  89.         OneEffectRec*                        List;
  90.         MyBoolean                                Stereo;
  91.  
  92.         /* list of commands that have been scheduled but haven't been executed yet. */
  93.         CommandConsCell*                ScanningGapListHead;
  94.         CommandConsCell*                ScanningGapListTail;
  95.         /* this is the current duration update index for the scanning gap list */
  96.         long                                        ExecutionIndex;
  97.  
  98.         /* track effect enable.  turns off processing, but command handling */
  99.         /* remains enabled (otherwise you couldn't turn processing back on) */
  100.         MyBoolean                                Enable;
  101.     };
  102.  
  103.  
  104. static CommandConsCell*        CommandConsFreeList = NIL;
  105.  
  106.  
  107. /* dispose of cached effect generator structures */
  108. void                                    FlushTrackEffectGeneratorInfo(void)
  109.     {
  110.         while (CommandConsFreeList != NIL)
  111.             {
  112.                 CommandConsCell*        Temp;
  113.  
  114.                 Temp = CommandConsFreeList;
  115.                 CommandConsFreeList = CommandConsFreeList->Next;
  116.                 ReleasePtr((char*)Temp);
  117.             }
  118.     }
  119.  
  120.  
  121. /* create a new track effect generator */
  122. TrackEffectGenRec*        NewTrackEffectGenerator(struct EffectSpecListRec* SpecList,
  123.                                                 long FramesPerSecond, MyBoolean DoingStereo,
  124.                                                 float InverseVolume, struct MainWindowRec* MainWindow,
  125.                                                 long ScanningGapWidthInEnvelopeTicks)
  126.     {
  127.         TrackEffectGenRec*    Generator;
  128.         OneEffectRec*                Appender;
  129.         long                                List;
  130.         long                                Scan;
  131.  
  132.         CheckPtrExistence(SpecList);
  133.         Generator = (TrackEffectGenRec*)AllocPtrCanFail(sizeof(TrackEffectGenRec),
  134.             "TrackEffectGenRec");
  135.         if (Generator == NIL)
  136.             {
  137.              FailurePoint1:
  138.                 return NIL;
  139.             }
  140.         Generator->List = NIL;
  141.         Generator->Stereo = DoingStereo;
  142.         Generator->ScanningGapListHead = NIL;
  143.         Generator->ScanningGapListTail = NIL;
  144.         Generator->Enable = True;
  145.  
  146.         /* this is the current envelope update index for removing things from the */
  147.         /* scanning gap list (i.e. the back edge of the scanning gap) */
  148.         /* by setting this negative, we cause the scanning gap to open. */
  149.         Generator->ExecutionIndex = - ScanningGapWidthInEnvelopeTicks;
  150.  
  151.         /* initialize accent trackers */
  152.         Generator->CurrentAccent1 = 0;
  153.         Generator->Accent1ChangeCountdown = 0;
  154.         Generator->Accent1Change = NewLinearTransition(0,0,1);
  155.         if (Generator->Accent1Change == NIL)
  156.             {
  157.              FailurePoint2:
  158.                 ReleasePtr((char*)Generator);
  159.                 goto FailurePoint1;
  160.             }
  161.         Generator->CurrentAccent2 = 0;
  162.         Generator->Accent2ChangeCountdown = 0;
  163.         Generator->Accent2Change = NewLinearTransition(0,0,1);
  164.         if (Generator->Accent2Change == NIL)
  165.             {
  166.              FailurePoint3:
  167.                 DisposeLinearTransition(Generator->Accent1Change);
  168.                 goto FailurePoint2;
  169.             }
  170.         Generator->CurrentAccent3 = 0;
  171.         Generator->Accent3ChangeCountdown = 0;
  172.         Generator->Accent3Change = NewLinearTransition(0,0,1);
  173.         if (Generator->Accent3Change == NIL)
  174.             {
  175.              FailurePoint4:
  176.                 DisposeLinearTransition(Generator->Accent2Change);
  177.                 goto FailurePoint3;
  178.             }
  179.         Generator->CurrentAccent4 = 0;
  180.         Generator->Accent4ChangeCountdown = 0;
  181.         Generator->Accent4Change = NewLinearTransition(0,0,1);
  182.         if (Generator->Accent4Change == NIL)
  183.             {
  184.              FailurePoint5:
  185.                 DisposeLinearTransition(Generator->Accent3Change);
  186.                 goto FailurePoint4;
  187.             }
  188.  
  189.         /* build list of thingers */
  190.         Appender = NIL;
  191.         List = GetEffectSpecListLength(SpecList);
  192.         for (Scan = 0; Scan < List; Scan += 1)
  193.             {
  194.                 OneEffectRec*                Effect;
  195.  
  196.                 /* allocate record */
  197.                 Effect = (OneEffectRec*)AllocPtrCanFail(sizeof(OneEffectRec),"OneEffectRec");
  198.                 if (Effect == NIL)
  199.                     {
  200.                      FailurePoint6:
  201.                         while (Generator->List != NIL)
  202.                             {
  203.                                 Effect = Generator->List;
  204.                                 Generator->List = Generator->List->Next;
  205.                                 switch (Effect->Type)
  206.                                     {
  207.                                         default:
  208.                                             EXECUTE(PRERR(ForceAbort,"NewTrackEffectGenerator:  bad effect type"));
  209.                                             break;
  210.                                         case eDelayEffect:
  211.                                             DisposeDelayLineProcessor(Effect->u.DelayEffect);
  212.                                             break;
  213.                                         case eNLProcEffect:
  214.                                             DisposeNLProcProcessor(Effect->u.NLProcEffect);
  215.                                             break;
  216.                                         case eFilterEffect:
  217.                                             DisposeFilterArrayProcessor(Effect->u.FilterEffect);
  218.                                             break;
  219.                                         case eAnalyzerEffect:
  220.                                             DisposeAnalyzer(Effect->u.AnalyzerEffect);
  221.                                             break;
  222.                                     }
  223.                                 ReleasePtr((char*)Effect);
  224.                             }
  225.                         DisposeLinearTransition(Generator->Accent4Change);
  226.                         goto FailurePoint5;
  227.                     }
  228.                 /* fill in fields */
  229.                 Effect->Type = GetEffectSpecListElementType(SpecList,Scan);
  230.                 switch (Effect->Type)
  231.                     {
  232.                         default:
  233.                             EXECUTE(PRERR(ForceAbort,"NewTrackEffectGenerator:  bad effect type"));
  234.                             break;
  235.                         case eDelayEffect:
  236.                             Effect->u.DelayEffect = NewDelayLineProcessor(
  237.                                 GetDelayEffectFromEffectSpecList(SpecList,Scan),FramesPerSecond);
  238.                             if (Effect->u.DelayEffect == NIL)
  239.                                 {
  240.                                  FailurePoint6b:
  241.                                     ReleasePtr((char*)Effect);
  242.                                     goto FailurePoint6;
  243.                                 }
  244.                             break;
  245.                         case eNLProcEffect:
  246.                             Effect->u.NLProcEffect = NewNLProcProcessor(
  247.                                 GetNLProcEffectFromEffectSpecList(SpecList,Scan),DoingStereo,
  248.                                 InverseVolume);
  249.                             if (Effect->u.NLProcEffect == NIL)
  250.                                 {
  251.                                     goto FailurePoint6b;
  252.                                 }
  253.                             break;
  254.                         case eFilterEffect:
  255.                             Effect->u.FilterEffect = NewFilterArrayProcessor(
  256.                                 GetFilterEffectFromEffectSpecList(SpecList,Scan),FramesPerSecond,
  257.                                 DoingStereo);
  258.                             if (Effect->u.FilterEffect == NIL)
  259.                                 {
  260.                                     goto FailurePoint6b;
  261.                                 }
  262.                             break;
  263.                         case eAnalyzerEffect:
  264.                             Effect->u.AnalyzerEffect = NewAnalyzer(MainWindow,
  265.                                 GetAnalyzerEffectFromEffectSpecList(SpecList,Scan),DoingStereo,
  266.                                 InverseVolume);
  267.                             if (Effect->u.AnalyzerEffect == NIL)
  268.                                 {
  269.                                     goto FailurePoint6b;
  270.                                 }
  271.                             break;
  272.                     }
  273.                 /* link */
  274.                 Effect->Next = NIL;
  275.                 if (Appender == NIL)
  276.                     {
  277.                         Generator->List = Effect;
  278.                     }
  279.                  else
  280.                     {
  281.                         Appender->Next = Effect;
  282.                     }
  283.                 Appender = Effect;
  284.             }
  285.         return Generator;
  286.     }
  287.  
  288.  
  289. /* dispose of a track effect generator */
  290. void                                    DisposeTrackEffectGenerator(TrackEffectGenRec* Generator)
  291.     {
  292.         CommandConsCell*        Scan;
  293.  
  294.         CheckPtrExistence(Generator);
  295.         Scan = Generator->ScanningGapListHead;
  296.         while (Scan != NIL)
  297.             {
  298.                 CommandConsCell*        Temp;
  299.  
  300.                 Temp = Scan;
  301.                 Scan = Scan->Next;
  302.                 Temp->Next = CommandConsFreeList;
  303.                 CommandConsFreeList = Temp;
  304.             }
  305.         DisposeLinearTransition(Generator->Accent1Change);
  306.         DisposeLinearTransition(Generator->Accent2Change);
  307.         DisposeLinearTransition(Generator->Accent3Change);
  308.         DisposeLinearTransition(Generator->Accent4Change);
  309.         while (Generator->List != NIL)
  310.             {
  311.                 OneEffectRec*                Temp;
  312.  
  313.                 Temp = Generator->List;
  314.                 Generator->List = Generator->List->Next;
  315.                 switch (Temp->Type)
  316.                     {
  317.                         default:
  318.                             EXECUTE(PRERR(ForceAbort,"DisposeTrackEffectGenerator:  bad effect type"));
  319.                             break;
  320.                         case eDelayEffect:
  321.                             DisposeDelayLineProcessor(Temp->u.DelayEffect);
  322.                             break;
  323.                         case eNLProcEffect:
  324.                             DisposeNLProcProcessor(Temp->u.NLProcEffect);
  325.                             break;
  326.                         case eFilterEffect:
  327.                             DisposeFilterArrayProcessor(Temp->u.FilterEffect);
  328.                             break;
  329.                         case eAnalyzerEffect:
  330.                             DisposeAnalyzer(Temp->u.AnalyzerEffect);
  331.                             break;
  332.                     }
  333.                 ReleasePtr((char*)Temp);
  334.             }
  335.         ReleasePtr((char*)Generator);
  336.     }
  337.  
  338.  
  339. /* generate effect cycle */
  340. void                                    ApplyTrackEffectGenerator(TrackEffectGenRec* Generator,
  341.                                                 largefixedsigned* Data, long NumFrames)
  342.     {
  343.         OneEffectRec*                Scan;
  344.  
  345.         CheckPtrExistence(Generator);
  346.         Scan = Generator->List;
  347.         if ((Scan != NIL) && Generator->Enable)
  348.             {
  349.                 float                                Accent1;
  350.                 float                                Accent2;
  351.                 float                                Accent3;
  352.                 float                                Accent4;
  353.  
  354.                 Accent1 = LargeBCD2Single(Generator->CurrentAccent1);
  355.                 Accent2 = LargeBCD2Single(Generator->CurrentAccent2);
  356.                 Accent3 = LargeBCD2Single(Generator->CurrentAccent3);
  357.                 Accent4 = LargeBCD2Single(Generator->CurrentAccent4);
  358.                 while (Scan != NIL)
  359.                     {
  360.                         switch (Scan->Type)
  361.                             {
  362.                                 default:
  363.                                     EXECUTE(PRERR(ForceAbort,"ApplyTrackEffectGenerator:  bad effect type"));
  364.                                     break;
  365.                                 case eDelayEffect:
  366.                                     UpdateDelayLineState(Scan->u.DelayEffect,Accent1,Accent2,Accent3,Accent4);
  367.                                     if (Generator->Stereo)
  368.                                         {
  369.                                             ApplyDelayLineStereo(Data,NumFrames,Scan->u.DelayEffect);
  370.                                         }
  371.                                      else
  372.                                         {
  373.                                             ApplyDelayLineMono(Data,NumFrames,Scan->u.DelayEffect);
  374.                                         }
  375.                                     break;
  376.                                 case eNLProcEffect:
  377.                                     UpdateNLProcState(Scan->u.NLProcEffect,Accent1,Accent2,Accent3,Accent4);
  378.                                     ApplyNLProc(Data,NumFrames,Scan->u.NLProcEffect);
  379.                                     break;
  380.                                 case eFilterEffect:
  381.                                     UpdateFilterArrayState(Scan->u.FilterEffect,Accent1,Accent2,Accent3,Accent4);
  382.                                     ApplyFilterArray(Data,NumFrames,Scan->u.FilterEffect);
  383.                                     break;
  384.                                 case eAnalyzerEffect:
  385.                                     ApplyAnalyzer(Data,NumFrames,Scan->u.AnalyzerEffect);
  386.                                     break;
  387.                             }
  388.                         Scan = Scan->Next;
  389.                     }
  390.             }
  391.     }
  392.  
  393.  
  394. /* hand off command to be handled by effect generator.  the command will be scheduled */
  395. /* to occur at the time ScanningGapFrontInEnvelopeTicks (which will be */
  396. /* ScanningGapWidthInEnvelopeTicks in the future from now). */
  397. MyBoolean                            TrackEffectHandleCommand(TrackEffectGenRec* Generator,
  398.                                                 struct NoteObjectRec* Command,
  399.                                                 long ScanningGapFrontInEnvelopeTicks)
  400.     {
  401.         CheckPtrExistence(Generator);
  402.         CheckPtrExistence(Command);
  403.         /* don't bother unless there are effects to process */
  404.         if (Generator->List != NIL)
  405.             {
  406.                 CommandConsCell*        Cell;
  407.  
  408.                 if (CommandConsFreeList != NIL)
  409.                     {
  410.                         Cell = CommandConsFreeList;
  411.                         CommandConsFreeList = CommandConsFreeList->Next;
  412.                     }
  413.                  else
  414.                     {
  415.                         Cell = (CommandConsCell*)AllocPtrCanFail(sizeof(CommandConsCell),
  416.                             "CommandConsCell");
  417.                         if (Cell == NIL)
  418.                             {
  419.                                 return False;
  420.                             }
  421.                     }
  422.  
  423.                 /* fill in data fields */
  424.                 Cell->Command = Command;
  425.                 Cell->StartTime = ScanningGapFrontInEnvelopeTicks;
  426.  
  427.                 /* insert into list */
  428.                 /* there is no need to sort, since the start time of commands can't */
  429.                 /* be adjusted.  just append to the list */
  430.                 Cell->Next = NIL;
  431.                 if (Generator->ScanningGapListTail == NIL)
  432.                     {
  433.                         Generator->ScanningGapListHead = Cell;
  434.                     }
  435.                  else
  436.                     {
  437.                         Generator->ScanningGapListTail->Next = Cell;
  438.                     }
  439.                 Generator->ScanningGapListTail = Cell;
  440.             }
  441.  
  442.         return True;
  443.     }
  444.  
  445.  
  446. /* increment duration timer.  this is called once per envelope tick to adjust */
  447. /* all of the parameter transition tracking devices */
  448. void                                    TrackEffectIncrementDurationTimer(TrackEffectGenRec* Generator,
  449.                                                 long NumDurationTicks)
  450.     {
  451.         CheckPtrExistence(Generator);
  452.         /* don't bother unless there are effects to process */
  453.         if ((Generator->List != NIL) && Generator->Enable)
  454.             {
  455.                 UpdateOne(&Generator->CurrentAccent1,Generator->Accent1Change,
  456.                     &Generator->Accent1ChangeCountdown,NumDurationTicks);
  457.                 UpdateOne(&Generator->CurrentAccent2,Generator->Accent2Change,
  458.                     &Generator->Accent2ChangeCountdown,NumDurationTicks);
  459.                 UpdateOne(&Generator->CurrentAccent3,Generator->Accent3Change,
  460.                     &Generator->Accent3ChangeCountdown,NumDurationTicks);
  461.                 UpdateOne(&Generator->CurrentAccent4,Generator->Accent4Change,
  462.                     &Generator->Accent4ChangeCountdown,NumDurationTicks);
  463.             }
  464.     }
  465.  
  466.  
  467. /* process commands in the queue that occur now.  this should be called after */
  468. /* queueing commands, but before incrementing the execution index, and before */
  469. /* processing the data, so that commands are handled at the beginning of a transition. */
  470. void                                    TrackEffectProcessQueuedCommands(TrackEffectGenRec* Generator)
  471.     {
  472.         CheckPtrExistence(Generator);
  473.         if (Generator->List != NIL)
  474.             {
  475.                 while ((Generator->ScanningGapListHead != NIL)
  476.                     && (Generator->ScanningGapListHead->StartTime <= Generator->ExecutionIndex))
  477.                     {
  478.                         CommandConsCell*        Cell;
  479.  
  480.                         /* since the start time of commands can't be adjusted, there should */
  481.                         /* never be a command that is strictly less than. */
  482.                         ERROR(Generator->ScanningGapListHead->StartTime < Generator->ExecutionIndex,
  483.                             PRERR(AllowResume,"TrackEffectProcessQueuedCommands:  early command"));
  484.                         /* unlink the cons cell */
  485.                         Cell = Generator->ScanningGapListHead;
  486.                         Generator->ScanningGapListHead = Generator->ScanningGapListHead->Next;
  487.                         if (Generator->ScanningGapListHead == NIL)
  488.                             {
  489.                                 Generator->ScanningGapListTail = NIL;
  490.                             }
  491.                         /* see what we're supposed to do with the command */
  492.                         switch (Cell->Command->Flags & ~eCommandFlag)
  493.                             {
  494.                                 default:
  495.                                     EXECUTE(PRERR(ForceAbort,
  496.                                         "TrackEffectProcessQueuedCommands:  bad command"));
  497.                                     break;
  498.                                 case eCmdSetEffectParam1: /* specify the new default effect parameter in <1l> */
  499.                                 case eCmdSetScoreEffectParam1:
  500.                                     Generator->CurrentAccent1 = Cell->Command->a.Command.Argument1;
  501.                                     Generator->Accent1ChangeCountdown = 0;
  502.                                     break;
  503.                                 case eCmdIncEffectParam1: /* add <1l> to the default effect parameter */
  504.                                 case eCmdIncScoreEffectParam1:
  505.                                     Generator->CurrentAccent1 += Cell->Command->a.Command.Argument1;
  506.                                     Generator->Accent1ChangeCountdown = 0;
  507.                                     break;
  508.                                 case eCmdSweepEffectParamAbs1: /* <1l> = new effect parameter, <2xs> = # of beats to get there */
  509.                                 case eCmdSweepScoreEffectParamAbs1:
  510.                                     SweepToNewValue(Generator->CurrentAccent1,Generator->Accent1Change,
  511.                                         &Generator->Accent1ChangeCountdown,Cell->Command->a.Command.Argument1,
  512.                                         Cell->Command->a.Command.Argument2);
  513.                                     break;
  514.                                 case eCmdSweepEffectParamRel1: /* <1l> = effect parameter adjust, <2xs> = # of beats to get there */
  515.                                 case eCmdSweepScoreEffectParamRel1:
  516.                                     SweepToAdjustedValue(Generator->CurrentAccent1,Generator->Accent1Change,
  517.                                         &Generator->Accent1ChangeCountdown,Cell->Command->a.Command.Argument1,
  518.                                         Cell->Command->a.Command.Argument2);
  519.                                     break;
  520.  
  521.                                 case eCmdSetEffectParam2: /* specify the new default effect parameter in <1l> */
  522.                                 case eCmdSetScoreEffectParam2:
  523.                                     Generator->CurrentAccent2 = Cell->Command->a.Command.Argument1;
  524.                                     Generator->Accent2ChangeCountdown = 0;
  525.                                     break;
  526.                                 case eCmdIncEffectParam2: /* add <1l> to the default effect parameter */
  527.                                 case eCmdIncScoreEffectParam2:
  528.                                     Generator->CurrentAccent2 += Cell->Command->a.Command.Argument1;
  529.                                     Generator->Accent2ChangeCountdown = 0;
  530.                                     break;
  531.                                 case eCmdSweepEffectParamAbs2: /* <1l> = new effect parameter, <2xs> = # of beats to get there */
  532.                                 case eCmdSweepScoreEffectParamAbs2:
  533.                                     SweepToNewValue(Generator->CurrentAccent2,Generator->Accent2Change,
  534.                                         &Generator->Accent2ChangeCountdown,Cell->Command->a.Command.Argument1,
  535.                                         Cell->Command->a.Command.Argument2);
  536.                                     break;
  537.                                 case eCmdSweepEffectParamRel2: /* <1l> = effect parameter adjust, <2xs> = # of beats to get there */
  538.                                 case eCmdSweepScoreEffectParamRel2:
  539.                                     SweepToAdjustedValue(Generator->CurrentAccent2,Generator->Accent2Change,
  540.                                         &Generator->Accent2ChangeCountdown,Cell->Command->a.Command.Argument1,
  541.                                         Cell->Command->a.Command.Argument2);
  542.                                     break;
  543.  
  544.                                 case eCmdSetEffectParam3: /* specify the new default effect parameter in <1l> */
  545.                                 case eCmdSetScoreEffectParam3:
  546.                                     Generator->CurrentAccent3 = Cell->Command->a.Command.Argument1;
  547.                                     Generator->Accent3ChangeCountdown = 0;
  548.                                     break;
  549.                                 case eCmdIncEffectParam3: /* add <1l> to the default effect parameter */
  550.                                 case eCmdIncScoreEffectParam3:
  551.                                     Generator->CurrentAccent3 += Cell->Command->a.Command.Argument1;
  552.                                     Generator->Accent3ChangeCountdown = 0;
  553.                                     break;
  554.                                 case eCmdSweepEffectParamAbs3: /* <1l> = new effect parameter, <2xs> = # of beats to get there */
  555.                                 case eCmdSweepScoreEffectParamAbs3:
  556.                                     SweepToNewValue(Generator->CurrentAccent3,Generator->Accent3Change,
  557.                                         &Generator->Accent3ChangeCountdown,Cell->Command->a.Command.Argument1,
  558.                                         Cell->Command->a.Command.Argument2);
  559.                                     break;
  560.                                 case eCmdSweepEffectParamRel3: /* <1l> = effect parameter adjust, <2xs> = # of beats to get there */
  561.                                 case eCmdSweepScoreEffectParamRel3:
  562.                                     SweepToAdjustedValue(Generator->CurrentAccent3,Generator->Accent3Change,
  563.                                         &Generator->Accent3ChangeCountdown,Cell->Command->a.Command.Argument1,
  564.                                         Cell->Command->a.Command.Argument2);
  565.                                     break;
  566.  
  567.                                 case eCmdSetEffectParam4: /* specify the new default effect parameter in <1l> */
  568.                                 case eCmdSetScoreEffectParam4:
  569.                                     Generator->CurrentAccent4 = Cell->Command->a.Command.Argument1;
  570.                                     Generator->Accent4ChangeCountdown = 0;
  571.                                     break;
  572.                                 case eCmdIncEffectParam4: /* add <1l> to the default effect parameter */
  573.                                 case eCmdIncScoreEffectParam4:
  574.                                     Generator->CurrentAccent4 += Cell->Command->a.Command.Argument1;
  575.                                     Generator->Accent4ChangeCountdown = 0;
  576.                                     break;
  577.                                 case eCmdSweepEffectParamAbs4: /* <1l> = new effect parameter, <2xs> = # of beats to get there */
  578.                                 case eCmdSweepScoreEffectParamAbs4:
  579.                                     SweepToNewValue(Generator->CurrentAccent4,Generator->Accent4Change,
  580.                                         &Generator->Accent4ChangeCountdown,Cell->Command->a.Command.Argument1,
  581.                                         Cell->Command->a.Command.Argument2);
  582.                                     break;
  583.                                 case eCmdSweepEffectParamRel4: /* <1l> = effect parameter adjust, <2xs> = # of beats to get there */
  584.                                 case eCmdSweepScoreEffectParamRel4:
  585.                                     SweepToAdjustedValue(Generator->CurrentAccent4,Generator->Accent4Change,
  586.                                         &Generator->Accent4ChangeCountdown,Cell->Command->a.Command.Argument1,
  587.                                         Cell->Command->a.Command.Argument2);
  588.                                     break;
  589.                                 case eCmdTrackEffectEnable:
  590.                                     Generator->Enable = (Cell->Command->a.Command.Argument1 < 0);
  591.                                     break;
  592.                             }
  593.                         /* dispose */
  594.                         Cell->Next = CommandConsFreeList;
  595.                         CommandConsFreeList = Cell;
  596.                     }
  597.  
  598.                 /* increment our scanning gap back edge clock, after scheduling commands */
  599.                 /* (this way, commands are scheduled on the beginning of the clock they */
  600.                 /* should occur on). */
  601.                 Generator->ExecutionIndex += 1;
  602.                 /* since this routine is only called when samples are being generated, */
  603.                 /* we don't have to worry about when to increment this counter */
  604.             }
  605.     }
  606.